package iot.core.manager.auth;


import iot.core.data.IdNameDto;
import iot.core.data.TreeViewNode;
import iot.core.data.entity.*;
import iot.core.data.mapper.*;
import iot.core.enums.AuthType;
import iot.core.exception.MyException;
import iot.core.manager.htcll.HTCtlManager;
import iot.core.manager.id.HTIDManager;
import iot.core.springboot.ApplicationUtils;
import iot.core.springboot.MyThreadLocal;
import iot.core.util.MyJSON;
import iot.core.util.MyStringUtil;
import iot.core.util.StreamUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Slf4j
public class AuthManager {

    HTUserLoginMapper htUserLoginMapper;
    HTUserMapper htUserMapper;
    HTUserDeptMapper htUserDeptMapper;
    HTUserRoleMapper htUserRoleMapper;

    HTMenuMapper htMenuMapper;
    HTPageMapper htPageMapper;
    HTPageAuthMapper htPageAuthMapper;

    HTCtlMapper htCtlMapper;
    HTActionMapper htActionMapper;

    HTRoleMenuMapper htRoleMenuMapper;
    private static volatile AuthManager instance = null;


    //2.构造方法设为 private
    public AuthManager() {
        htUserLoginMapper= ApplicationUtils.getBean(HTUserLoginMapper.class);
        htUserMapper= ApplicationUtils.getBean(HTUserMapper.class);
        htUserDeptMapper= ApplicationUtils.getBean(HTUserDeptMapper.class);
        htUserRoleMapper= ApplicationUtils.getBean(HTUserRoleMapper.class);
        htMenuMapper= ApplicationUtils.getBean(HTMenuMapper.class);
        htPageMapper= ApplicationUtils.getBean(HTPageMapper.class);
        htPageAuthMapper= ApplicationUtils.getBean(HTPageAuthMapper.class);
        htCtlMapper= ApplicationUtils.getBean(HTCtlMapper.class);
        htActionMapper= ApplicationUtils.getBean(HTActionMapper.class);
        htRoleMenuMapper= ApplicationUtils.getBean(HTRoleMenuMapper.class);
    }

    public static AuthManager getInstance() {
        if (instance == null) {
            synchronized (AuthManager.class) {
                if (instance == null) {
                    instance = new AuthManager();
                }
            }
        }
        return instance;
    }

    public HTUserLogin getSuByToken(String token )
    {
       var qw=htUserLoginMapper.getQueryWrapper();
       qw.eq("token",token);
        var m=htUserLoginMapper.selectOne(qw);

        if (m!=null)
        {
            m.setHTRoles(  MyJSON.parseArray(    m.getHTRole_Data(),IdNameDto.class)  );
        }
        return m;
    }
        //生成密码
    public String createPwd(String ename,String pwd)
    {
        var s=iot.core.util.MD5.get(ename + pwd);
        return s;
    }
    //生成Token
    public String createToken(long lgid)
    {
        var s = HTIDManager.getInstance().nextGuid().toString();
        return s;
    }

    //用户密码检查
    //返回机构
    public List<HTDeptBaseDto> loginCheck(LoginUserPwdDto loginInfo )
    {
        var ckPWD = createPwd(loginInfo.getEName(), loginInfo.getPWD());
        var qw=htUserMapper.getQueryWrapper();
        qw.eq("EName",loginInfo.getEName());

        var muser=htUserMapper.selectOne(qw);
        if(muser==null)
        {
            throw new MyException("用户不存在");
        }
        if(!muser.getPWD().toUpperCase().equals(ckPWD.toUpperCase()) ) {
            throw new MyException("密码错误");
        }

        var l=htUserDeptMapper.getUserDept(muser.getId() );

        return l;

    }
    @Transactional(rollbackFor = Exception.class)
    //登录
    public  String login(LoginDto mm){
        var loginUserPwdDto = new LoginUserPwdDto();
        loginUserPwdDto.setEName(mm.getEName());
        loginUserPwdDto.setPWD(mm.getPWD());

        var ldept = loginCheck(loginUserPwdDto );

        HTDeptBaseDto mdept = null;
        if (ldept.size() == 0)
        {
            throw new MyException("没有机构");
        }
        if (mm.getHTDept_Id() > 0)
        {
            ldept = StreamUtil.list(ldept,a->a.getId().equals(mm.getHTDept_Id())) ;
        }
        if (mm.getHTPlat_Id() > 0)
        {
            ldept = StreamUtil.list(ldept,a->a.getHTPlat_Id().equals(mm.getHTPlat_Id())) ;
        }
        if (ldept.size()!=1)
        {
            throw new MyException("请登录机构");
        }
        mdept = ldept.get(0);

        var qwuser=htUserMapper.getQueryWrapper();
        qwuser.eq("ename",mm.getEName() );
        var muser=htUserMapper.selectOne(qwuser);

        var su= MyThreadLocal.get().getSu();
        su.setId(HTIDManager.getInstance().nextLong() );
        su.setToken(  createToken(su.getId() ) );
        su.setName(muser.getName());
        su.setCrt_UId(muser.getId() );
        su.setCrt_DId(mdept.getId() );
        su.setHTDept_Id(mdept.getId());
        su.setHTDept_Name(mdept.getName() );
        su.setHTPlat_Id(mdept.getHTPlat_Id());
        su.setIsOnline(true);
        su.setLoginWay(mm.getLoginWay());

        su.setCrt_DT(new Date());
        su.setEdt_DT(new Date());
        su.setLogout_DT(new Date());
        if (mm.getExtra().size()>0 )
        {
            if (mm.getExtra().containsKey("AppVer"))
            {
                su.setAppver( mm.getExtra().get("AppVer")  );
            }
            if (mm.getExtra().containsKey("IMSI"))
            {
                su.setAppver( mm.getExtra().get("IMSI")  );
            }

            su.setExtra( MyJSON.toJSONString(mm.getExtra()) );
        }
        var log = MyThreadLocal.get().getMylog();
        log.setName(muser.getName());
        muser.setCrt_UId(muser.getId());
        log.setCrt_DId(mdept.getId());
        log.setHTDept_Id(mdept.getId());
        log.setHTDept_Name(mdept.getName());
        log.setHTPlat_Id(su.getHTPlat_Id());


        var lrole =htUserRoleMapper.getRole(muser.getId(),mdept.getId() );
        su.setHTRoles(lrole);
        su.setHTRole_Data(MyJSON.toJSONString(lrole));

        var qwlogin=htUserLoginMapper.getQueryWrapper();
        qwlogin.eq("IsOnline",true);
        qwlogin.eq("Crt_UId",su.getCrt_UId() );
        qwlogin.eq("LoginWay",su.getLoginWay() );
        var lold=htUserLoginMapper.selectList(qwlogin);
        for(var mold:lold){
            mold.setIsOnline(false);
            mold.setLogout_DT(new Date());
            mold.setLogout_Memo( String.format("被 %s 踢下线",su.getIP() ));
            htUserLoginMapper.updateById(mold);//不设置其他字段
        }

        htUserLoginMapper.insert(su);//不设置其他字段
        //缓存menu
        //缓存url

        return su.getToken();
    }
    public  List<TreeViewNode> getMenuByHTPlatIdAsync(long HTPlat_Id){
         var qwMenu=htMenuMapper.getQueryWrapper();
         qwMenu.eq("HTPlat_Id",HTPlat_Id);
         var l=htMenuMapper.selectList(qwMenu);
         List<Long> lpageid=new ArrayList<>();
         lpageid=l.stream().map(a->a.getHTPage_Id()).distinct().collect(Collectors.toList());
         List<HTPageAuth> lpageauth=new ArrayList<>();
         List<HTPage> lpage=new ArrayList<>();
         var r=new ArrayList<TreeViewNode>();
         if(lpageid.size()>0){
             lpage=htPageMapper.selectBatchIds(lpageid);
             lpageid=lpage.stream().map(a->a.getId()).collect(Collectors.toList());
             if(lpageid.size()>0){
                 var qwpa=htPageAuthMapper.getQueryWrapper();
                 qwpa.in("HTPage_Id",lpageid);
                 lpageauth=htPageAuthMapper.selectList(qwpa);
             }
         }
        addChildMenu(r,null,l,lpage,lpageauth);
         return r;
    }
    TreeViewNode createByPage( HTMenu mmenu, HTPage mpage, List<HTPageAuth> lpageauth) throws RuntimeException
    {

        var tnc = new TreeViewNode();
        htMenuMapper.entityToDto(mmenu, tnc);
        tnc.setCode(mpage.getCode());
        tnc.setName(mpage.getName());
        tnc.setImgUrl(mpage.getImgUrl());


        for(var m : lpageauth)
        {
            var tnc2 = new TreeViewNode();
            tnc2.setLX("权限");
            tnc2.setObj(m.getUrls());
            htPageAuthMapper.entityToDto(m, tnc2);
            tnc.getChildren().add(tnc2);
        }
        return tnc;
    }
    void addChildMenu(List<TreeViewNode> r,TreeViewNode tn, List< HTMenu> l,
                  List< HTPage> lpage,
                  List< HTPageAuth> lpageauth
    )
    {
        var pid=tn==null?0L:tn.getId();
        l.stream().filter(a->a.getPId().equals(pid))
                .sorted(Comparator.comparing(HTMenu::getSortNo) )
                .collect(Collectors.toList())
                .forEach(mmenu->{
                    if(mmenu.getHTPage_Id()>0){
                        var mpage=StreamUtil.get(lpage,a->a.getId().equals(mmenu.getHTPage_Id()));
                        if(mpage!=null&&!mpage.isDeleted()){
                            var lpageAuth2=StreamUtil.list(lpageauth,a->a.getHTPage_Id().equals(mpage.getId()), Comparator.comparing(HTPageAuth::getSortNo) );
                            var tnc = createByPage(mmenu,mpage, lpageAuth2);
                            if(tn!=null){
                                tn.getChildren().add(tnc);
                            }else {
                                r.add(tnc);
                            }
                            addChildMenu(r,tnc, l, lpage, lpageauth);

                        }
                    }else{
                        var tnc = new TreeViewNode();
                        htMenuMapper.entityToDto(mmenu, tnc);
                        tnc.setObj( mmenu.getHTPage_Id().toString() );
                        if(tn!=null){
                            tn.getChildren().add(tnc);
                        }else {
                            r.add(tnc);
                        }
                        addChildMenu(r,tnc, l, lpage, lpageauth);
                    }
                });
    }


    public   int createPageByCtl(CreatePageByCtlDto mm)
    {


        var mctl = htCtlMapper.selectById(mm.getId());
        var qwaction=htActionMapper.getQueryWrapper();
        qwaction.eq("CtlFullName",mctl.getCtlFullName() );
        qwaction.eq("AuthType","Auth" );
        qwaction.orderBy(true,true,"Id");
        var laction=htActionMapper.selectList(qwaction);
        var arr = mctl.getCtlFullName().split("\\.");
        var Code = arr[arr.length - 1].replace("Controller", "").toLowerCase();

        var mpage = new  HTPage();
        mpage.setId(mm.isReserveId()?mctl.getId():HTIDManager.getInstance().nextLong());
        mpage.setCode(Code);
        mpage.setMemo(mctl.getMemo());
        mpage.setImgUrl("");

        if (mm.isReserveId())
        {
            var mpage2=htPageMapper.selectById(mpage.getId());
            if (mpage2!= null)
            {
                return 0;
            }
        }
        htPageMapper.insert(mpage, true );
        if ("1".equals(mm.getMode() ) )//完全权限
        {
            var Urls = "";
            for(var mation : laction)
            {
                Urls += mation.getFullUrl() + ",";
            }
            Urls= MyStringUtil.trimEnd(Urls,",");

            var mauth = new  HTPageAuth();
            mauth.setId(mm.isReserveId()?(mctl.getId()+1):HTIDManager.getInstance().nextLong());
            mauth.setHTPage_Id(mpage.getId());
            mauth.setCode("*");
            mauth.setUrls(Urls);
            mauth.setName("完全权限");
            mauth.setMemo("");
            mauth.setSortNo(10L);
            htPageAuthMapper.insert(mauth,true);

        }
        else
        {
            for (var mation: laction)
            {
                var mauth = new  HTPageAuth();
                mauth.setId(mm.isReserveId()?mation.getId():HTIDManager.getInstance().nextLong());
                mauth.setHTPage_Id(mpage.getId());
                mauth.setCode(mation.getFullUrl());
                mauth.setUrls(mation.getFullUrl());
                mauth.setName(mation.getName());
                mauth.setMemo("");
                mauth.setSortNo( mation.getId()-mctl.getId() );
                htPageAuthMapper.insert(mauth,true);

            }

        }

        return 1;

    }

    public boolean HasUrl(HTUserLogin su,String url)
    {
        if(su.getCrt_UId().equals(1000L)){
            return true;
        }
        url = url.toLowerCase();
        var mact = HTCtlManager.getInstance().getAction(url);
        if (mact == null)
        {
            return true;
        }
        if (mact.getAuthType().equals(AuthType.None) )
        {
            return true;
        }

        if (mact.getAuthType().equals(AuthType.Login) )
        {
            return su.getCrt_UId()>0L;
        }

        var rids = su.getHTRoles().stream().map( a -> a.getId()).collect(Collectors.toList()) ;

        var lurls=htRoleMenuMapper.getRolesMenu(rids);
        String finalUrl = url;
        var murl= StreamUtil.get(lurls,a->a.equals(finalUrl));
        if (murl!=null)
        {
            return true;
        }
        var l2 = new ArrayList<String>();
        AtomicBoolean bfound= new AtomicBoolean(false);
        lurls.forEach(murl2->{
            if(murl2.indexOf(",")>0){
                var arr=murl2.split(",");
                for(var i=0;i<arr.length;i++){
                    if(arr[i].trim().equals(finalUrl)){
                        bfound.set(true);
                        return ;
                    }
                    l2.add( arr[i].trim() );
                }

            }
        });
        if(bfound.get()){
            return true;
        }

        lurls.addAll(l2);

        var ib = url.lastIndexOf("/");
        url= url.substring(0, ib)+"/*";
        var finalUrl2=url;
        murl= StreamUtil.get(lurls,a->a.equals(finalUrl2));
        if (murl!=null)
        {
            return true;
        }
        return false;
    }

    public void start() {


    }


}
